package xpn.platform.common.repository;

import java.io.Serializable;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.rest.webmvc.PersistentEntityResource;
import org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler;
import org.springframework.data.web.PagedResourcesAssembler;
import org.springframework.hateoas.PagedModel;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import com.google.common.base.Strings;

/**
 * 配合XpnRespository为所有DAO添加的自定义的公共行为，提供相应的RESTful的访问服务。
 *
 * @author bobatkm Oct 3, 2017
 *
 * @param <T>
 * @param <ID>
 */
public abstract class XpnRepositoryController<T, ID extends Serializable> {
	@Autowired
	private XpnRepository<T, ID> dao;

	@SuppressWarnings("rawtypes")
	@Autowired
	private PagedResourcesAssembler pagedResourcesAssembler;

	/**
	 * 根据指定的jpql查询符合条件的记录，并返回记录分页数据。
	 *
	 * 参数描述请参见XpnRepository的filter方法{@link XpnRepository}
	 */
	@SuppressWarnings("unchecked")
	@RequestMapping(value = "filter", method = RequestMethod.GET, params = { "clazz", "jpql" })
	public PagedModel<T> filterByJpql(@RequestParam(value = "jpql", required = true) String jpql,
			@RequestParam(value = "clazz", required = true) String clazz, Pageable pageable, Sort sort,
			PersistentEntityResourceAssembler resourceAssembler) {
		Page<T> page = dao.filterByJpql(jpql, pageable, sort);
		return pagedResourcesAssembler.toModel(page, resourceAssembler);
	}

	@SuppressWarnings("unchecked")
	@RequestMapping(value = "count", method = RequestMethod.GET, params = { "jpql" })
	public Object count(@RequestParam(value = "jpql", required = true) String jpql) {
		Object count = dao.countByJpql(jpql);
		return count;
	}

	@RequestMapping(value = "executeJpql", method = RequestMethod.GET, params = { "jpql" })
	public Object executeJpql(@RequestParam(value = "jpql", required = true) String jpql) {
		Object result = dao.executeJpql(jpql);
		return result;
	}

	/**
	 * 查找指定实体（@param id指定）的儿子集合，并返回记录分页数据。
	 *
	 * 重载Spring data rest缺省的controller，目的是使用graph以提高性能。
	 *
	 * 其它参数描述请参见XpnRepository的filter方法 {@link XpnRepository}
	 */
	@SuppressWarnings("unchecked")
	@RequestMapping(value = "{id}/children", method = RequestMethod.GET, params = { "clazz", "childrenJpql" })
	public PagedModel<T> findChildren(@PathVariable(required = true) ID id,
			@RequestParam(value = "clazz", required = true) String clazz,
			@RequestParam(value = "childrenJpql", required = false) String childrenJpql, Pageable pageable, Sort sort,
			PersistentEntityResourceAssembler resourceAssembler) {

		// 调用filter返回结果
		Page<T> page = dao.filterByJpql(childrenJpql, pageable, sort);
		return pagedResourcesAssembler.toModel(page, resourceAssembler);
	}

	/**
	 * 根据指定的sql查询符合条件的记录，并返回记录分页数据。
	 *
	 * 参数描述请参见XpnRepository的filter方法{@link XpnRepository}
	 */
	@SuppressWarnings("unchecked")
	@RequestMapping(value = "filter", method = RequestMethod.GET, params = { "sql" })
	public PagedModel<T> filterBySql(@RequestParam(value = "sql", required = true) String sql, Pageable pageable,
			Sort sort, PersistentEntityResourceAssembler resourceAssembler) {

		Page<T> page = dao.filterBySql(sql, null, pageable, sort);
		return pagedResourcesAssembler.toModel(page, resourceAssembler);
	}

	/**
	 * 根据id查询符合条件的记录并返回。
	 *
	 * 重载Spring data rest缺省的controller，目的是使用join fetch以提高性能。
	 *
	 * 参数描述请参见XpnRepository的findOne方法 {@link XpnRepository}
	 */
	@RequestMapping(value = "{id}", method = RequestMethod.GET, params = { "clazz", "jpql" })
	public PersistentEntityResource getOne(@PathVariable(required = true) ID id,
			@RequestParam(value = "clazz", required = true) String clazz,
			@RequestParam(value = "jpql", required = true) String jpql,
			PersistentEntityResourceAssembler resourceAssembler) {
		T entity = null;
		if (Strings.isNullOrEmpty(clazz) || Strings.isNullOrEmpty(jpql)) {
			entity = dao.getOne(id);
		} else {
			entity = dao.findOneByJpql(jpql, id);
		}
		return resourceAssembler.toFullResource(entity);
	}

	/**
	 * 根据instanceId查询符合条件的记录并返回。
	 *
	 */
	@RequestMapping(value = "", method = RequestMethod.GET, params = { "clazz", "jpql", "instanceId", "todoId" })
	public PersistentEntityResource getOneByProcessInstanceId(
			@RequestParam(value = "clazz", required = true) String clazz,
			@RequestParam(value = "jpql", required = true) String jpql,
			@RequestParam(value = "instanceId", required = true) String instanceId,
			PersistentEntityResourceAssembler resourceAssembler) {

		// 构造完整的查询jpql
		jpql = jpql + " where o.xpnProcessInstanceId=" + instanceId;
		T entity = dao.findOneByJpql(jpql);

		return resourceAssembler.toFullResource(entity);
	}

	@SuppressWarnings("unchecked")
	@RequestMapping(value = "batchsave", method = RequestMethod.POST)
	public PagedModel<T> batchsave(
			@RequestBody(required = false) BatchSaveEntity<T> batchsaveEntiry,
			PersistentEntityResourceAssembler resourceAssembler) {
		List<T> page = dao.batchsave(batchsaveEntiry);
		return null;

		//return pagedResourcesAssembler.toResource(page, resourceAssembler);
	}
}
